
#include "AuthorityCertificateManager.hpp"


AuthorityCertificateManager::AuthorityCertificateManager(std::string &file, std::string &chain)
{
	path certPath(file);
	path chainPath(chain);

	std::cout << "AuthorityCertificateManager" << std::endl;


	this->m_authority = readCredentialsFromFile(certPath, false);
	chainList.push_back(this->m_authority);

	if (!chain.empty())
	{
		Certificate *chain = readCredentialsFromFile(chainPath, false);
		chainList.push_back(chain);
	}

	this->leafPair  = buildKeysForClient();
}

bool AuthorityCertificateManager::isOCSPAddress(boost::asio::ip::tcp::endpoint &endpoint)
{
	boost::asio::ip::address address      = endpoint.address();
	return this->m_authority->isOCSPAddress(address);
}

bool AuthorityCertificateManager::isValidTarget(boost::asio::ip::tcp::endpoint &end,
        bool wildcardOK)
{
	return true;
}

void AuthorityCertificateManager::getCertificateForTarget(boost::asio::ip::tcp::endpoint &endpoint,
        bool wildcardOK,
        X509 *serverCertificate,
        Certificate **cert,
        std::list<Certificate*> **chainList)
{
	X509_NAME *serverName   = X509_get_subject_name(serverCertificate);
	X509_NAME *issuerName   = X509_get_subject_name(m_authority->getCert());

	X509 *m_request;

	char skod[500];
//printf("NAME=%s\n\r", X509_NAME_oneline(serverName,skod,199));
	X509_NAME_oneline(serverName,skod,499);

	std::string cn(skod);
	std::string filename = "cert/" + cn.substr(cn.find("/CN=") + 4);
	std::map<std::string,X509*>::const_iterator itr = m_CertList.find(cn);


	if(boost::filesystem::exists(filename))
	{

		BIO *rsaPublicBio = BIO_new(BIO_s_file());
		if(BIO_read_filename(rsaPublicBio, filename.c_str()))
		{
			m_request = PEM_read_bio_X509(rsaPublicBio, NULL, 0, NULL);
		}
		/*
			}

			if(itr != m_CertList.end())
			{
		//		std::cout << "found key cn=" << cn << std::endl;
				m_request = itr->second;
		*/
	}
	else
	{
		m_request           = X509_new();

		std::cout << "new key cn=" << cn << std::endl;
		X509_set_version(m_request, 3);
		X509_set_subject_name(m_request, serverName);
		X509_set_issuer_name(m_request, issuerName);

		ASN1_INTEGER_set(X509_get_serialNumber(m_request), generateRandomSerial());
		X509_gmtime_adj(X509_get_notBefore(m_request), -365);
		X509_gmtime_adj(X509_get_notAfter(m_request), (long)60*60*24*365);
		X509_set_pubkey(m_request, this->leafPair);

		X509_sign(m_request, m_authority->getKey(), EVP_sha1());

		m_CertList[cn] = m_request;

//		std::string filename = "cert.skod";
		BIO* rsaPublicBio = BIO_new_file(filename.c_str(), "w");
		PEM_write_bio_X509(rsaPublicBio, m_request);

		PEM_write_bio_RSAPrivateKey(rsaPublicBio, EVP_PKEY_get1_RSA(this->leafPair), NULL, NULL, 0, NULL, NULL);
		BIO_free(rsaPublicBio);

	}

	Certificate *leaf = new Certificate();
	leaf->setCert(m_request);
	leaf->setKey(this->leafPair);

	*cert  = leaf;
	*chainList = &(this->chainList);
//  *chain = this->authority;
}

unsigned int AuthorityCertificateManager::generateRandomSerial()
{
	unsigned int serial;
	RAND_bytes((unsigned char*)&serial, sizeof(serial));
	return serial;
}

EVP_PKEY* AuthorityCertificateManager::buildKeysForClient()
{

	if(boost::filesystem::exists("rsa.key"))
	{
		EVP_PKEY *rsaKeyPairSpec = EVP_PKEY_new();
		BIO *rsaPrivateBio = BIO_new(BIO_s_file());
		RSA *rsaKeyPair;
		if(BIO_read_filename(rsaPrivateBio, "rsa.key"))
		{
		}
		EVP_PKEY_assign_RSA(rsaKeyPairSpec, rsaKeyPair);
		PEM_read_bio_RSAPrivateKey(rsaPrivateBio,&rsaKeyPair,NULL,NULL);
		EVP_PKEY_assign_RSA(rsaKeyPairSpec, rsaKeyPair);
		return rsaKeyPairSpec;
	}

	EVP_PKEY *rsaKeyPairSpec = EVP_PKEY_new();

	RSA *rsaKeyPair          = RSA_generate_key(2048, RSA_F4, NULL, NULL);

	EVP_PKEY_assign_RSA(rsaKeyPairSpec, rsaKeyPair);

	BIO* rsaPrivateBio = BIO_new_file("rsa.key", "w");

	PEM_write_bio_RSAPrivateKey(rsaPrivateBio, rsaKeyPair, NULL, NULL, 0, NULL, NULL);
	BIO_free(rsaPrivateBio);
	return rsaKeyPairSpec;
}
